package com.zbest.zpay.acctrans.component;

import java.util.Date;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.zbest.common.lang.base.Money;
import com.zbest.common.lang.util.CoreDateUtils;
import com.zbest.zpay.acctrans.common.exception.AccTransRuntimeException;
import com.zbest.zpay.acctrans.common.util.BalanceTagUtils;
import com.zbest.zpay.acctrans.dal.mapper.InnerBalanceMapper;
import com.zbest.zpay.acctrans.dal.mapper.InnerDetailMapper;
import com.zbest.zpay.acctrans.dal.model.InnerBalance;
import com.zbest.zpay.acctrans.dal.model.InnerDetail;
import com.zbest.zpay.acctrans.dal.model.InnerInf;
import com.zbest.zpay.acctrans.dal.model.TransJnl;
import com.zbest.zpay.acctrans.enums.CapStsFlg;
import com.zbest.zpay.acctrans.enums.DebitCreditHoldFlag;
import com.zbest.zpay.acctrans.enums.UpdBalFlg;
import com.zbest.zpay.acctrans.enums.biz.AcctransBizCode;

public class InnerAccountWithdrawComponent {

    private static final Logger logger = LoggerFactory
            .getLogger(InnerAccountWithdrawComponent.class);
    /**
     * 内部户余额操作DAO
     */
    @Autowired
    private InnerBalanceMapper innerBalanceMapper;

    /**
     * 创建内部户余额信息
     */
    @Autowired
    private CreateInnerAccountBalanceComponent createInnerAccountBalanceComponent;

    /**
     * 创建内部户收支明细信息
     */
    @Autowired
    private InnerDetailMapper innerDetailMapper;

    public void execute(TransJnl transJnl, InnerInf drInnerInf) {
        logger.info("[INNER ACCOUNT WITHDRAW!]");
        if (transJnl == null) {
            logger.info("AccountTransJnl不能为空");
            throw new AccTransRuntimeException(AcctransBizCode.ACT_FIELD_NOT_NULL, "AccountTransJnl不能为空");
        }
        String jrnNo = transJnl.getJrnNo();
        String actNo = transJnl.getDrActNo();
        String actTyp = transJnl.getDrActTyp();
        String actDat = transJnl.getActDat();
        String iacBalDrt = drInnerInf.getIacBalDrt();

        String updBalFlg = drInnerInf.getUpdBalFlg();
        InnerBalance innerAccountBalance = null;
        if (StringUtils.equals(updBalFlg, UpdBalFlg.IS_UPDATE.getCode())) {
            /** 在内部账户余额信息表中判断是否存在该账户的余额信息,如果存在再 for update该记录，避免死锁 */
            long retNum = innerBalanceMapper.qryCntByInActNo(actNo);
            if (retNum == 1) {
                innerAccountBalance = innerBalanceMapper.qryByInActNoForUpd(actNo);
            }
            if (innerAccountBalance == null) {
                createInnerAccountBalanceComponent.execute(actTyp, actNo, iacBalDrt, actDat, jrnNo);
                innerAccountBalance = innerBalanceMapper.qryByInActNoForUpd(actNo);
            } else {
                long curActBal = innerAccountBalance.getCurActBal();
                Money bal = new Money(curActBal, Money.DEFAULT_CURRENCY);
                boolean tagCheckRet = BalanceTagUtils.verifyBalanceTag(actNo, bal, innerAccountBalance.getBalTag());
                if (!(tagCheckRet)) {
                    throw new AccTransRuntimeException(
                            AcctransBizCode.ACT_ACCOUNT_CURBAL_ILLEGAL, "账户余额金额值非法");
                }
            }

            if (StringUtils.equals(iacBalDrt, DebitCreditHoldFlag.CREDIT_FLAG.getCode())) {
                innerActBalCrUpdate(transJnl, innerAccountBalance);

            }
            if (StringUtils.equals(iacBalDrt, DebitCreditHoldFlag.DEBIT_FLAG.getCode())) {
                innerActBalDrUpdate(transJnl, innerAccountBalance);
            }

        }

        writeInnerActDrCrDetail(transJnl, drInnerInf, innerAccountBalance);

        logger.info("[内部账户支取成功]");
    }

    public void innerActBalDrUpdate(TransJnl accountTransJnl, InnerBalance innerAccountBalance) {
        String jrnNo = accountTransJnl.getJrnNo();
        String actNo = innerAccountBalance.getInActNo();
        String actTyp = innerAccountBalance.getInActTyp();
        String actDat = accountTransJnl.getActDat();
        String iacBalDrt = innerAccountBalance.getIacBalDrt();
        logger.info("[DR UPD!]");

        Money lastBalAmt = new Money(innerAccountBalance.getLastActBal(), Money.DEFAULT_CURRENCY);
        Money txAmt = new Money(accountTransJnl.getFctTxAmt(), Money.DEFAULT_CURRENCY);
        Money curBal = new Money(innerAccountBalance.getCurActBal(), Money.DEFAULT_CURRENCY);
        String lastActDate = innerAccountBalance.getUpdDat();
        Money lastDrBal = new Money(innerAccountBalance.getLastDrBal(), Money.DEFAULT_CURRENCY);
        Money lastCrBal = new Money(innerAccountBalance.getLastCrBal(), Money.DEFAULT_CURRENCY);
        Money drBal = new Money(innerAccountBalance.getDrBal(), Money.DEFAULT_CURRENCY);
        Money crBal = new Money(innerAccountBalance.getCrBal(), Money.DEFAULT_CURRENCY);
        drBal = drBal.add(txAmt);

        if (Long.valueOf(actDat) > Long.valueOf(lastActDate)) {
            lastActDate = actDat;
            lastBalAmt = new Money(innerAccountBalance.getCurActBal(), Money.DEFAULT_CURRENCY);
            lastDrBal = new Money(innerAccountBalance.getDrBal(), Money.DEFAULT_CURRENCY);
            lastCrBal = new Money(innerAccountBalance.getCrBal(), Money.DEFAULT_CURRENCY);
            drBal = txAmt;
            crBal = new Money(0, Money.DEFAULT_CURRENCY);
        } else if (Long.valueOf(actDat) < Long.valueOf(lastActDate)) {
            lastBalAmt = lastBalAmt.add(txAmt);
            lastDrBal = lastDrBal.add(txAmt);
        }
        Money acBal = curBal.add(txAmt);

        /** 预留内部账户是否允许红字 */

        String crtBalTag = BalanceTagUtils.createBalanceTag(innerAccountBalance.getInActNo(), acBal);

        innerAccountBalance.setLastActBal(lastBalAmt.getCent());
        innerAccountBalance.setCurActBal(acBal.getCent());
        innerAccountBalance.setBalTag(crtBalTag);
        innerAccountBalance.setUpdDat(lastActDate);
        innerAccountBalance.setUpdJrn(jrnNo);
        innerAccountBalance.setInActNo(actNo);
        innerAccountBalance.setLastDrBal(lastDrBal.getCent());
        innerAccountBalance.setLastCrBal(lastCrBal.getCent());
        innerAccountBalance.setCrBal(crBal.getCent());
        innerAccountBalance.setDrBal(drBal.getCent());
        int retCd = innerBalanceMapper.updateBalByInActNo(innerAccountBalance);
        if (retCd == 0) {
            throw new AccTransRuntimeException(AcctransBizCode.ACT_INNER_ACCOUNT_UPDBAL_FAIL,
                    "更新内部账户余额失败");
        }
    }

    public void innerActBalCrUpdate(TransJnl accountTransJnl, InnerBalance innerAccountBalance) {
        String jrnNo = accountTransJnl.getJrnNo();
        String actNo = innerAccountBalance.getInActNo();
        String actTyp = innerAccountBalance.getInActTyp();
        String actDat = accountTransJnl.getActDat();
        String iacBalDrt = innerAccountBalance.getIacBalDrt();
        logger.info("[CR UPD!]");

        Money lastBalAmt = new Money(innerAccountBalance.getLastActBal(), Money.DEFAULT_CURRENCY);
        Money txAmt = new Money(accountTransJnl.getFctTxAmt(), Money.DEFAULT_CURRENCY);
        Money curBal = new Money(innerAccountBalance.getCurActBal(), Money.DEFAULT_CURRENCY);
        Money uavaBal = new Money(innerAccountBalance.getUavaBal(), Money.DEFAULT_CURRENCY);

        String lastActDate = innerAccountBalance.getUpdDat();
        Money lastDrBal = new Money(innerAccountBalance.getLastDrBal(), Money.DEFAULT_CURRENCY);
        Money lastCrBal = new Money(innerAccountBalance.getLastCrBal(), Money.DEFAULT_CURRENCY);
        Money drBal = new Money(innerAccountBalance.getDrBal(), Money.DEFAULT_CURRENCY);
        Money crBal = new Money(innerAccountBalance.getCrBal(), Money.DEFAULT_CURRENCY);
        drBal = drBal.add(txAmt);

        if (Long.valueOf(actDat) > Long.valueOf(lastActDate)) {
            lastActDate = actDat;
            lastBalAmt = new Money(innerAccountBalance.getCurActBal(), Money.DEFAULT_CURRENCY);
            lastDrBal = new Money(innerAccountBalance.getDrBal(), Money.DEFAULT_CURRENCY);
            lastCrBal = new Money(innerAccountBalance.getCrBal(), Money.DEFAULT_CURRENCY);
            drBal = txAmt;
            crBal = new Money(0, Money.DEFAULT_CURRENCY);
        } else if (Long.valueOf(actDat) < Long.valueOf(lastActDate)) {
            lastBalAmt = lastBalAmt.subtract(txAmt);
            lastCrBal = lastCrBal.add(txAmt);
        }
        Money acBal = curBal.subtract(txAmt);
        /** 预留内部账户透支额度检查 */
        String crtBalTag = BalanceTagUtils.createBalanceTag(innerAccountBalance.getInActNo(), acBal);
        innerAccountBalance.setLastActBal(lastBalAmt.getCent());
        innerAccountBalance.setCurActBal(acBal.getCent());
        innerAccountBalance.setBalTag(crtBalTag);
        innerAccountBalance.setUpdDat(lastActDate);
        innerAccountBalance.setUpdJrn(jrnNo);
        innerAccountBalance.setInActNo(actNo);
        innerAccountBalance.setLastCrBal(lastCrBal.getCent());
        innerAccountBalance.setLastDrBal(lastDrBal.getCent());
        innerAccountBalance.setCrBal(crBal.getCent());
        innerAccountBalance.setDrBal(drBal.getCent());
        int retCd = innerBalanceMapper.updateBalByInActNo(innerAccountBalance);
        if (retCd == 0) {
            throw new AccTransRuntimeException(AcctransBizCode.ACT_INNER_ACCOUNT_UPDBAL_FAIL,
                    "更新内部账户余额失败");
        }
    }

    public void writeInnerActDrCrDetail(TransJnl accountTransJnl, InnerInf innerInf, InnerBalance innerAccountBalance) {
        logger.info("[WRITE  INNER ACCOUNT DETAIL RECORD!]");

        InnerDetail innerAccountDetail = new InnerDetail();
        innerAccountDetail.setSysDat(CoreDateUtils.yyyymmdd(new Date()));
        innerAccountDetail.setSysTim(CoreDateUtils.hh24miss(new Date()));
        innerAccountDetail.setJrnNo(accountTransJnl.getJrnNo());
        innerAccountDetail.setJrnSeq(accountTransJnl.getJrnSeq());
        innerAccountDetail.setInActNo(innerInf.getInActNo());
        innerAccountDetail.setInActTyp(innerInf.getInActTyp());
        innerAccountDetail.setOldTxDt(accountTransJnl.getOldTxDt());
        innerAccountDetail.setOldTxTm(accountTransJnl.getOldTxTm());
        innerAccountDetail.setActDat(accountTransJnl.getActDat());
        innerAccountDetail.setTxCd(accountTransJnl.getTxCd());
        innerAccountDetail.setBusTyp(accountTransJnl.getBusTyp());
       // innerAccountDetail.setTxOppTyp(accountTransJnl.getDrActTyp());
        innerAccountDetail.setTxOppCd(accountTransJnl.getDrUsrId());
        innerAccountDetail.setOppAc(accountTransJnl.getDrActNo());
        innerAccountDetail.setDcFlg(DebitCreditHoldFlag.DEBIT_FLAG.getCode());
        innerAccountDetail.setDrAmt(accountTransJnl.getFctTxAmt());
        innerAccountDetail.setUpdBalFlg(innerInf.getUpdBalFlg());
        innerAccountDetail.setTxDesc(accountTransJnl.getTxDesc());
        innerAccountDetail.setOrdTyp(accountTransJnl.getOrdTyp());
        innerAccountDetail.setOrdNo(accountTransJnl.getOrdNo());
        innerAccountDetail.setTxAmt(accountTransJnl.getOrdAmt());
        innerAccountDetail.setFeeAmt(accountTransJnl.getFeeAmt());
        innerAccountDetail.setMercId(accountTransJnl.getMercId());
        innerAccountDetail.setVchNoTyp(accountTransJnl.getVchNoTyp());
        innerAccountDetail.setVchNo(accountTransJnl.getVchNo());
        innerAccountDetail.setRmk(accountTransJnl.getTxDesc());
        innerAccountDetail.setBusCnl(accountTransJnl.getBusCnl());
        innerAccountDetail.setSysCnl(accountTransJnl.getSysCnl());
        innerAccountDetail.setIacBalDrt(innerInf.getIacBalDrt());

        if (StringUtils.equals(innerInf.getUpdBalFlg(),
                UpdBalFlg.IS_UPDATE.getCode())) {
            innerAccountDetail.setBal(innerAccountBalance.getCurActBal());
            innerAccountDetail.setUpdBalFlg(UpdBalFlg.IS_UPDATE.getCode());
            innerAccountDetail.setInCapSts(CapStsFlg.CAP_STATUS_NORMAL.getCode());
        } else {
            innerAccountDetail.setUpdBalFlg(UpdBalFlg.NOT_UPDATE.getCode());
            innerAccountDetail.setInCapSts(CapStsFlg.CAP_STATUS_NOT.getCode());
        }
        innerDetailMapper.insert(innerAccountDetail);
    }

}
